package pers.xiaojun.boot.module.system.service.dept;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pers.xiaojun.boot.mybatis.core.convert.PageConvert;
import pers.xiaojun.boot.common.exception.BusinessException;
import pers.xiaojun.boot.common.util.CollectionUtils;
import pers.xiaojun.boot.module.system.controller.dept.vo.post.PostQueryReqVO;
import pers.xiaojun.boot.module.system.controller.dept.vo.post.PostSaveReqVO;
import pers.xiaojun.boot.module.system.dao.entity.dept.PostDO;
import pers.xiaojun.boot.module.system.dao.mapper.dept.PostMapper;
import pers.xiaojun.boot.mybatis.core.query.LambdaQueryWrapperX;

import java.util.*;

import static pers.xiaojun.boot.module.system.constants.BusinessCodeConstants.*;


/**
 * 岗位服务实现类
 *
 * @author xiaojun
 * @since 2025-11-02
 */
@Service
@RequiredArgsConstructor
public class PostServiceImpl extends ServiceImpl<PostMapper, PostDO> implements PostService {

    private final UserPostService userPostService;

    @Override
    public PostDO savePost(PostSaveReqVO saveVO) {
        validatePostBasicInfo(null, saveVO.getName(), saveVO.getCode());

        PostDO post = BeanUtil.toBean(saveVO, PostDO.class);
        this.baseMapper.insert(post);

        return post;
    }

    @Override
    public PostDO updatePost(PostSaveReqVO updateVO) {
        validatePostExists(updateVO.getId());

        validatePostBasicInfo(updateVO.getId(), updateVO.getName(), updateVO.getCode());

        PostDO post = BeanUtil.toBean(updateVO, PostDO.class);
        this.baseMapper.updateById(post);

        return post;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removePostById(Long postId) {
        validatePostExists(postId);

        this.baseMapper.deleteById(postId);

        // 删除 用户岗位 下与当前岗位相关的数据
        userPostService.removeUserPostByPostId(postId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removePostByIds(Collection<Long> postIds) {
        List<PostDO> posts = this.baseMapper.selectByIds(postIds);

        // 校验岗位是否存在
        if (posts.size() != postIds.size()) {
            Set<Long> notFindIds = Sets.difference(
                    new HashSet<>(postIds),
                    CollectionUtils.convertSet(posts, PostDO::getId)
            );
            throw new BusinessException(POST_NOT_EXISTS.getCode(), StrUtil.format("岗位Id:{}不存在", notFindIds));
        }

        this.baseMapper.deleteByIds(postIds);

        userPostService.removeUserPostByPostIds(postIds);
    }

    @Override
    public PostDO getPostById(Long postId) {
        return validatePostExists(postId);
    }

    @Override
    public Page<PostDO> listPostsPage(PostQueryReqVO queryVO) {
        return this.baseMapper.selectPage(PageConvert.INSTANCE.toPage(queryVO), new LambdaQueryWrapperX<PostDO>()
                .likeIfPresent(PostDO::getName, queryVO.getName())
                .likeIfPresent(PostDO::getCode, queryVO.getCode())
                .eqIfPresent(PostDO::getStatus, queryVO.getStatus())
                .orderByAsc(PostDO::getSort)
        );
    }

    @Override
    public PostDO validatePostExists(Long postId) {
        PostDO post = this.baseMapper.selectById(postId);
        if (post == null) {
            throw new BusinessException(POST_NOT_EXISTS);
        }
        return post;
    }

    /**
     * 岗位基础信息校验
     *
     * @param postId   岗位Id
     * @param postName 岗位名称
     * @param postCode 岗位代码
     */
    public void validatePostBasicInfo(Long postId, String postName, String postCode) {
        PostDO post = this.baseMapper.selectByName(postName);
        if (post != null && !post.getId().equals(postId)) {
            throw new BusinessException(POST_NAME_EXISTS);
        }

        post = this.baseMapper.selectByCode(postCode);
        if (post != null && !post.getId().equals(postId)) {
            throw new BusinessException(POST_CODE_EXISTS);
        }
    }

}
